﻿namespace _01单例模式.反射破坏单例模式
{
    /// <summary>
    /// 解决多线程发生指令重排的问题
    /// </summary>
    public class SingleLayMan2
    {
        /*
        //1、new 在内存中开辟空间
        //2、 执行构造函数 创建对象
        //3、 把空间指向我们的对像

        //多线程会发生问题  "指令重拍"本应执行顺序为1、2、3，实际执行顺序为1、3、2

        //解决该问题需要 给定义的私有局部变量加关键字 volatile //意思不稳定的 ，可变的 加该关键字可以避免指令重排
        */

        //2、声明静态字段  存储我们唯一的对象实例
        private volatile static SingleLayMan2? _singleLayMan;
        private static object _oj = new object();
        //私有化构造函数
        private SingleLayMan2()
        {

        }
       
        /// <summary>
        /// //解决多线程安全问题，双重锁定，减少系统消耗，节约资源
        /// </summary>
        public static SingleLayMan2 GetSingleLayMan()
        {
            if (_singleLayMan == null)
            {
                lock (_oj)
                {
                    if (_singleLayMan == null)
                    {
                        _singleLayMan = new SingleLayMan2();
                        Console.WriteLine("我被创建了一次！");
                    }
                }
            }           
            return _singleLayMan;
        }        
    }

    public class SingleLayManTest2
    {
        public static void FactTestReflection()
        {
            var singleLayMan2= SingleLayMan2.GetSingleLayMan();

            var type = Type.GetType("_01单例模式.反射破坏单例模式.SingleLayMan2");
            //获取私有的构造函数
            var ctors = type?.GetConstructors(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            //执行构造函数
            SingleLayMan2 singleLayMan = (SingleLayMan2)ctors[0].Invoke(null);
            Console.WriteLine(singleLayMan2.GetHashCode());
            Console.WriteLine(singleLayMan.GetHashCode());

            //通过两次反射依然可以创建对象，具体过程是new没有执行，跨国了new 直接去执行构造函数创建对象了

            //解决办法 搞个标记 只有第一次会创建对象，后面都不会创建
        }
    }
}
